package com.alks.function.service.impl.biocontrol.deptwork;

import com.alibaba.excel.util.StringUtils;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.entity.data.entity.CpLastSlipDetail;
import com.alks.entity.data.entity.CpLastSlipHead;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.biocontrol.deptwork.LastDetDto;
import com.alks.function.data.dto.biocontrol.deptwork.LastSlipDetDto;
import com.alks.function.data.dto.biocontrol.deptwork.LastStkDto;
import com.alks.function.data.request.biocontrol.deptwork.LastInDetRequest;
import com.alks.function.data.request.biocontrol.deptwork.LastInRequest;
import com.alks.function.data.request.biocontrol.deptwork.LastStkRequest;
import com.alks.function.mapper.biocontrol.deptwork.BC_DW_CpLastSlipDetailMapper;
import com.alks.function.mapper.biocontrol.deptwork.BC_DW_CpLastSlipHeadMapper;
import com.alks.function.service.biocontrol.deptwork.ILastInService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class LastInServiceImpl extends ServiceImpl<BC_DW_CpLastSlipDetailMapper, CpLastSlipDetail> implements ILastInService {
    private final BC_DW_CpLastSlipHeadMapper headMapper;
    private final BC_DW_CpLastSlipDetailMapper detailMapper;
    private final RedisService redisService;

    private final String cfmFlag = "Y";
    private final String outType = "O";

    @Override
    @AutoPageAop
    public ResponseInfo getLastHeadQuery(LastStkRequest request, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        List<LastStkDto> dtos = headMapper.getLastInHeadQuery(request, companyId, slipType);
        Page<LastStkDto> page = (Page<LastStkDto>) dtos;
        /*获取数量和*/
        BigDecimal qtySum = headMapper.getLastInQtySum(request, companyId, slipType);
        /*封装数据*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        map.put("qtySum", qtySum);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo lastHeadCheck(String slipNo, String slipType) {
        /*修改数据*/
        LambdaUpdateWrapper<CpLastSlipHead> wrapper = new LambdaUpdateWrapper<CpLastSlipHead>()
                .eq(CpLastSlipHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpLastSlipHead::getSlipNo, slipNo)
                .eq(CpLastSlipHead::getSlipType, slipType)
                .set(CpLastSlipHead::getCfmFlag, "Y")
                .set(CpLastSlipHead::getCfmDate, LocalDateTime.now())
                .set(CpLastSlipHead::getCfmUser, UserIdThread.get().getUserName());
        headMapper.update(null, wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public LastDetDto getLastDetQuery(String slipNo, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*查询头数据*/
        LambdaQueryWrapper<CpLastSlipHead> wrapper = new LambdaQueryWrapper<CpLastSlipHead>()
                .eq(CpLastSlipHead::getCompanyId, companyId)
                .eq(CpLastSlipHead::getSlipType, slipType)
                .eq(CpLastSlipHead::getSlipNo, slipNo);
        CpLastSlipHead head = headMapper.selectOne(wrapper);
        if (head==null){
            return new LastDetDto();
        }
        LastDetDto dto = BeanUtil.copyBean(head, LastDetDto.class);
        /*补充明细数据*/
        List<LastSlipDetDto> detList = detailMapper.lastDetQuery(slipNo, companyId);
        if (outType.equals(slipType)) {
            /*出库数据填充*/
            List<String> sizeNoList = detList.stream().map(CpLastSlipDetail::getSizeNo).collect(Collectors.toList());
            String lastNo = head.getLastNo();
            String stkName = head.getStkName();
            List<Map<String, Object>> stkList = detailMapper.stkQuery(lastNo, sizeNoList, companyId,stkName);
            Map<Object, Object> stkMap = stkList.stream()
                    .collect(Collectors.toMap(a -> a.get("sizeNo"), a -> a.get("stkQty")));
            for (LastSlipDetDto detDto : detList) {
                detDto.setStkQty((BigDecimal) stkMap.get(detDto.getSizeNo()));
            }
        }
        dto.setDetails(detList);
        /*求和*/
        if (detList != null && !detList.isEmpty()) {
            BigDecimal qtySum = detList.stream()
                    .map(CpLastSlipDetail::getQty)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            dto.setQtySum(qtySum);
        } else {
            dto.setQtySum(BigDecimal.ZERO);
        }
        return dto;
    }

    @Override
    @Transactional
    public String lastAdd(LastInRequest request, String slipType) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        String userName = tokenDTO.getUserName();
        String slipNo = request.getSlipNo();
        String lastNo = request.getLastNo();
        if (StringUtils.isBlank(request.getSlipNo())) {
            /*新建表头数据*/
            slipNo = slipCreat(request, userName, companyId, slipType);
        } else {
            /*校验主表数据是否存在*/
            CpLastSlipHead head = lastSlipNoValid(slipNo, companyId);
            lastNo = head.getLastNo();
        }
        if (request.getDetail() != null) {
            /*判断入参是否完整*/
            List<LastInDetRequest> emptyList = request.getDetail().stream()
                    .filter(a -> StringUtils.isBlank(a.getSizeNo()))
                    .collect(Collectors.toList());
            if (ArrayUtils.isNoEmpyt(emptyList)) {
                throw new ServiceErrorException("号码不能为空");
            }
            /*删除原有数据*/
            LambdaQueryWrapper<CpLastSlipDetail> wrapper=new LambdaQueryWrapper<CpLastSlipDetail>()
                    .eq(CpLastSlipDetail::getSlipNo, slipNo)
                    .eq(CpLastSlipDetail::getCompanyId,companyId);
            detailMapper.delete(wrapper);
            /*写入明细数据*/
            BigDecimal seqNo = BigDecimal.ZERO;
            for (LastInDetRequest rd : request.getDetail()) {
                CpLastSlipDetail detail = new CpLastSlipDetail();
                detail.setCompanyId(companyId);
                detail.setSlipNo(slipNo);
                detail.setLastNo(lastNo);
                detail.setSizeNo(rd.getSizeNo());
                detail.setSizeType(rd.getSizeType());
                detail.setQty(rd.getQty());
                detail.setSeqNo(seqNo);
                detailMapper.insert(detail);
                seqNo = seqNo.add(BigDecimal.ONE);
            }
        }
        return slipNo;
    }

    private CpLastSlipHead lastSlipNoValid(String slipNo, String companyId) {
        LambdaQueryWrapper<CpLastSlipHead> headWrapper = new LambdaQueryWrapper<CpLastSlipHead>()
                .eq(CpLastSlipHead::getSlipNo, slipNo)
                .eq(CpLastSlipHead::getCompanyId, companyId);
        CpLastSlipHead head = headMapper.selectOne(headWrapper);
        if (head == null) {
            throw new ServiceErrorException("订单号不存在");
        }
        return head;
    }

    /**
     * 新建主表数据
     *
     * @param request   入参
     * @param userName  创建人
     * @param companyId 公司ID
     * @param slipType  单据类型
     * @return 生成的订单号
     */
    private String slipCreat(LastInRequest request, String userName, String companyId, String slipType) {
        lastHeadUpCheck(request);
        /*新建订单号*/
        String slipNo = redisService.slipNoCreat("", "XT", 4);
        /*补全数据*/
        CpLastSlipHead head = BeanUtil.copyBean(request, CpLastSlipHead.class);
        head.setSlipNo(slipNo);
        head.setSlipType(slipType);
        head.setSysUser(userName);
        head.setSysDate(LocalDateTime.now());
        head.setCompanyId(companyId);
        headMapper.insert(head);
        return slipNo;
    }

    /**
     * 主表增改前置字段空值校验
     *
     * @param request 入参
     */
    private static void lastHeadUpCheck(LastInRequest request) {
        if (StringUtils.isBlank(request.getLastNo())) {
            throw new ServiceErrorException("顶栏楦头号不能为空");
        }
        if (StringUtils.isBlank(request.getStkName()) || StringUtils.isBlank(request.getStkNo())) {
            throw new ServiceErrorException("仓库不能为空");
        }
        if (request.getSlipDate() == null) {
            throw new ServiceErrorException("单据日期不能为空");
        }
    }

    @Override
    @Transactional
    public String lastUp(LastInRequest request, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        String slipNo = request.getSlipNo();
        String lastNo = request.getLastNo();
        if (StringUtils.isBlank(slipNo)) {
            throw new ServiceErrorException("单据号不能为空");
        }
        /*入参校验*/
        lastHeadUpCheck(request);
        LambdaUpdateWrapper<CpLastSlipHead> headWrapper = new LambdaUpdateWrapper<CpLastSlipHead>()
                .eq(CpLastSlipHead::getCompanyId, companyId)
                .eq(CpLastSlipHead::getSlipNo, request.getSlipNo())
                .eq(CpLastSlipHead::getSlipType, slipType);
        CpLastSlipHead head = headMapper.selectOne(headWrapper);
        if (head == null) {
            throw new ServiceErrorException("订单不存在");
        }
        if (cfmFlag.equals(head.getCfmFlag())) {
            throw new ServiceErrorException("已检核数据不能修改");
        }
        /*明细表数据更新*/
        List<LastInDetRequest> reqDet = request.getDetail();
        if (ArrayUtils.isNoEmpyt(reqDet)) {
            /*数据检核*/
            List<LastInDetRequest> partEmptyList = reqDet.stream()
                    .filter(a -> StringUtils.isBlank(a.getSizeNo()))
                    .collect(Collectors.toList());
            if (ArrayUtils.isNoEmpyt(partEmptyList)) {
                throw new ServiceErrorException("明细号码不能为空");
            }
        }
        /*删除旧数据*/
        LambdaQueryWrapper<CpLastSlipDetail> wrapper = new LambdaQueryWrapper<CpLastSlipDetail>()
                .eq(CpLastSlipDetail::getSlipNo, request.getSlipNo())
                .eq(CpLastSlipDetail::getCompanyId, companyId);
        detailMapper.delete(wrapper);
        if (ArrayUtils.isNoEmpyt(reqDet)) {
            /*准备序号*/
            BigDecimal seqNo = BigDecimal.ZERO;
            /*写入数据*/
            for (LastInDetRequest det : reqDet) {
                CpLastSlipDetail detail = new CpLastSlipDetail();
                detail.setCompanyId(companyId);
                detail.setQty(det.getQty());
                detail.setSlipNo(slipNo);
                detail.setLastNo(lastNo);
                detail.setSizeNo(det.getSizeNo());
                detail.setSizeType(det.getSizeType());
                detail.setSeqNo(seqNo);
                try {
                    detailMapper.insert(detail);
                }catch (DuplicateKeyException e){
                    throw new ServiceErrorException("存在重复数据");
                }
                seqNo = seqNo.add(BigDecimal.ONE);
            }
        }
        /*更新数据*/
        headWrapper.set(CpLastSlipHead::getSlipDate, request.getSlipDate())
                .set(CpLastSlipHead::getLastNo, lastNo)
                .set(CpLastSlipHead::getInOutType, request.getInOutType())
                .set(CpLastSlipHead::getStkNo, request.getStkNo())
                .set(CpLastSlipHead::getStkName, request.getStkName())
                .set(CpLastSlipHead::getVendorNo, request.getVendorNo())
                .set(CpLastSlipHead::getVendorName, request.getVendorName())
                .set(CpLastSlipHead::getRemark, request.getRemark());
        headMapper.update(null, headWrapper);
        return slipNo;
    }

    @Override
    @Transactional
    public ResponseInfo lastDelete(String slipNo, String slipType) {
        /*判断是否检核*/
        LambdaQueryWrapper<CpLastSlipHead> headWrapper = new LambdaQueryWrapper<CpLastSlipHead>()
                .eq(CpLastSlipHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpLastSlipHead::getSlipNo, slipNo)
                .eq(CpLastSlipHead::getSlipType, slipType);
        CpLastSlipHead head = headMapper.selectOne(headWrapper);
        if (cfmFlag.equals(head.getCfmFlag())) {
            throw new ServiceErrorException("已检核数据不能修改");
        }
        /*删除主表*/
        headMapper.delete(headWrapper);
        /*删除明细*/
        LambdaQueryWrapper<CpLastSlipDetail> detailWrapper = new LambdaQueryWrapper<CpLastSlipDetail>()
                .eq(CpLastSlipDetail::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(CpLastSlipDetail::getSlipNo, slipNo);
        detailMapper.delete(detailWrapper);
        return ResponseInfo.ok();
    }

    @Override
    public void lastDetDelete(String slipNo, String seqNo, String slipType) {
        String companyId = UserIdThread.get().getCompanyId();
        /*判断是否可以删除*/
        CpLastSlipHead head = lastSlipNoValid(slipNo, companyId);
        if (cfmFlag.equals(head.getCfmFlag())) {
            throw new ServiceErrorException("已检核数据不能删除");
        }
        /*删除明细*/
        LambdaQueryWrapper<CpLastSlipDetail> detailWrapper = new LambdaQueryWrapper<CpLastSlipDetail>()
                .eq(CpLastSlipDetail::getCompanyId, companyId)
                .eq(CpLastSlipDetail::getSlipNo, slipNo)
                .eq(CpLastSlipDetail::getSeqNo, seqNo);
        detailMapper.delete(detailWrapper);
    }
}
